package com.knowif.backend.service;

import com.alibaba.fastjson.JSONObject;
import com.knowif.backend.util.CertSSLUtil;
import com.knowif.backend.util.IPUtil;
import com.knowif.dao.TUserMapper;
import com.knowif.dao.TopicMapper;
import com.knowif.enumInfo.UserOrderStatusEnum;
import com.knowif.pojo.*;
import com.knowif.service.UserPayOrder_service;
import com.knowif.service.UserWechat_service;
import com.knowif.system.model.RestBean;
import com.knowif.util.WechatMiniUtil;
import com.knowif.util.commonUtil.SecurityUtil;
import com.knowif.util.commonUtil.StringUtil;
import com.knowif.util.paramUtil.DateFormatUtil;
import com.knowif.util.parseUtil.XmlUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.*;

@Service
@Slf4j
public class UserOrderFlowService {
    @Value("${wechat.config.constant.key}")
    private String key;
    @Value("${wechat.config.constant.mchId}")
    private String mchId;
    @Value("${wechat.config.constant.appid}")
    private String appid;
    @Value("${wechat.config.constant.appSecret}")
    private String appSecret;
    @Value("${wechat.config.constant.payNotityUrl}")
    private String payNotityUrl;
    @Value("${tencent.pay.cert}")
    private String cert;
    @Value("${tencent.pay.key}")
    private String certKey;

    @Autowired
    private ServletContext servletContext;
    @Autowired
    private WechatMiniUtil wechatMiniUtil;
    @Autowired
    private UserWechat_service userWechat_service;

    @Autowired
    private UserPayOrder_service userPayOrder_service;
    @Autowired
    private TUserMapper tUserMapper;
    @Autowired
    private TopicMapper topicMapper;

    /**
     * @param openid：支付者的openid
     * @param body：购买信息
     * */
    public RestBean<?> wechatPayOrder(String openid, String body, HttpServletRequest request,int userOrderId) {
        String out_trade_no = ("" + System.currentTimeMillis() + StringUtil.getRandom(5)).toUpperCase();
        UserOrder userOrder = userPayOrder_service.selectUserOrderById(userOrderId);
        if(userOrder == null){
            return RestBean.buildError("没有此订单",RestBean.not_authorized);
        }
        if(userOrder.getStatus() != UserOrderStatusEnum.BEGIN.getState()){//判断该订单是否为未支付状态
            return RestBean.build(RestBean.not_authorized,"该订单已过期");
        }
        String ip = IPUtil.getIpAddress(request);
        UserOrderFlow userOrderFlow = userPayOrder_service.selectUserOrderFlowByUserOrderId(userOrderId);

        int price = new Double(userOrder.getPrice()*100).intValue();
        if(price <= 0){
            return RestBean.buildError("订单金额设置错误");
        }
        SortedMap<String, Object> params = new TreeMap<String, Object>();
        params.put("mch_id", mchId);
        params.put("appid", appid);
        params.put("trade_type", "JSAPI");
        params.put("out_trade_no", out_trade_no);//微信支付订单号
        params.put("nonce_str", StringUtil.getRandom(10));
        params.put("openid", openid);
        params.put("body", body);
        params.put("total_fee",price);//
        params.put("spbill_create_ip", ip);
        params.put("notify_url", payNotityUrl);
        String sign = StringUtil.getMiniSign(params).append("key=" + key).toString();
        params.put("sign", SecurityUtil.stringToMD5(sign).toUpperCase());
        String xml = StringUtil.toMiniWechatPayXml(params);
        try {
            URL url = new URL("https://api.mch.weixin.qq.com/pay/unifiedorder");
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("POST");
            con.setUseCaches(false);
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
            OutputStream out = con.getOutputStream();
            out.write(xml.getBytes());
            out.flush();
            out.close();
            InputStream in = null;
            if (con.getResponseCode() == 200) {
                in = con.getInputStream();
            } else {
                in = con.getErrorStream();
                String temp = "";
                String result = "";
                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                while ((temp = br.readLine()) != null) {
                    result += temp;
                }
                log.info(result);
                return RestBean.buildError("wechat pay system error");
            }

            String temp = "";
            String result = "";
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            while ((temp = br.readLine()) != null) {
                result += temp;
            }
            log.info(result);
            Map<String, String> map = XmlUtils.xmlToMap(result);
            if ("SUCCESS".equals(map.get("result_code")) && "SUCCESS".equals(map.get("return_code"))) {
                String timeStamp = System.currentTimeMillis() + "";
                timeStamp = timeStamp.substring(0, 10);
                SortedMap<String, Object> data = new TreeMap<String, Object>();
                String random = StringUtil.getRandom(10);
                data.put("appId", appid);
                data.put("nonceStr", random);
                data.put("package", "prepay_id=" + map.get("prepay_id"));
                data.put("signType", "MD5");
                data.put("timeStamp", timeStamp);
                JSONObject json = new JSONObject();
                json.put("sign", SecurityUtil.stringToMD5(StringUtil.getMiniSign(data).append("key=" + key).toString()).toUpperCase());
                json.put("out_trade_no", out_trade_no);
                json.put("prepay_id", map.get("prepay_id"));
                json.put("nonceStr", random);
                json.put("timeStamp", timeStamp);
                servletContext.removeAttribute("prepay_id");
                servletContext.setAttribute("prepay_id", map.get("prepay_id"));
                if(userOrderFlow == null){
                    userOrderFlow = new UserOrderFlow();
                    userOrderFlow.setPayMoney(Double.parseDouble((price / 100 ) + ""));
                    userOrderFlow.setPayType(0);
                    userOrderFlow.setStatus(UserOrderStatusEnum.BEGIN.getState());
                    userOrderFlow.setWechatTradeNo(out_trade_no);
                    userOrderFlow.setIsSuccess(0);//支付是否成功 0、未支付成功， 1、支付成功
                    userOrderFlow.setOperation("下单未支付");
                    userOrderFlow.setUserOrderId(userOrderId);
                    userPayOrder_service.insertUserOrderFlow(userOrderFlow);
                }else{
                    userOrderFlow.setWechatTradeNo(out_trade_no);//创建时间可更新
                    userPayOrder_service.updateUserOrderFlow(userOrderFlow);
                }
                return RestBean.buildSuccess(json);
            }else{
                return RestBean.buildError("order check error");
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return RestBean.buildError("wechat pay system error");
    }


    /**
     * 退款--------
     * @param payTotal:支付金额
     * @param refundFee 退款金额
     * @param refundDesc 退款备注
     * */
    public RestBean<?> payRefund(String payOrderNumber,int payTotal,int refundFee,String notifyUrl,String refundDesc){

        UserOrderFlow userOrderFlow = userPayOrder_service.selectUserOrderFlowByWechatTradeNo(payOrderNumber);
        if(userOrderFlow == null){
            return RestBean.build(RestBean.not_code,"没有此订单号");
        }
        SortedMap<String, Object> params = new TreeMap<String, Object>();
        String out_refund_no = ""+System.currentTimeMillis()+StringUtil.getRandom(5);//必须存起来
        params.put("appid",appid);
        params.put("mch_id",mchId);
        params.put("nonce_str",StringUtil.getRandom(32));
        params.put("out_trade_no",payOrderNumber);
        params.put("out_refund_no",out_refund_no);//退款单号
        params.put("total_fee",payTotal);//
        params.put("refund_fee",refundFee);
        params.put("notify_url",notifyUrl);
        log.info("total_fee ===========================>" + payTotal);
        params.put("refund_desc",refundDesc);//退款原因
        String sign = StringUtil.getMiniSign(params).append("key=" + key).toString();//key必须加一个
        params.put("sign", SecurityUtil.stringToMD5(sign).toUpperCase());
        String xml = StringUtil.toMiniWechatPayXml(params);
        log.info(xml);
        try {
            URL url = new URL("https://api.mch.weixin.qq.com/secapi/pay/refund");
            HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
            con.setRequestMethod("POST");
            con.setUseCaches(false);
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setSSLSocketFactory(new CertSSLUtil().getSocketFactoryPEM(cert,certKey));

            con.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
            OutputStream out = con.getOutputStream();
            out.write(xml.getBytes());
            out.flush();
            out.close();
            InputStream in = null;
            if (con.getResponseCode() == 200) {
                in = con.getInputStream();
            } else {
                in = con.getErrorStream();
                String temp = "";
                String result = "";
                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                while ((temp = br.readLine()) != null) {
                    result += temp;
                }
                log.info(result);
                return RestBean.buildError("wechat pay system error");
            }

            String temp = "";
            String result = "";
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            while ((temp = br.readLine()) != null) {
                result += temp;
            }
            log.info(result);
            return RestBean.buildSuccess("refunding...");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return RestBean.buildError();
    }


    /**
     * 微信支付异步处理方法
     * */
    public void wechatPayResult(HttpServletRequest request, HttpServletResponse response){
        try {
            BufferedReader reader = request.getReader();
            String temp = "";
            StringBuffer inputString = new StringBuffer();
            while ((temp = reader.readLine()) != null) {
                inputString.append(temp);
            }
            reader.close();
            log.info("回调参数:" + inputString);
            Map<String, String> resultMap = XmlUtils.xmlToMap(inputString.toString());
            SortedMap<String, Object> map = new TreeMap<String, Object>();
            map.putAll(resultMap);
            String sign = (String) map.get("sign");
            map.remove("xml");
            map.remove("sign");
            String securitySign = SecurityUtil.stringToMD5(StringUtil.getMiniSign(map).append("key=" + key).toString()).toUpperCase();//payKey 需要替换成微信支付中的商家API key
            if(securitySign.equals(sign)){
                map.put("sign",sign);
                if ("SUCCESS".equals(map.get("return_code")) && "SUCCESS".equals(map.get("result_code"))){
                    log.info("验证回调通过");
                    //这里是SUCCESS已经支付成功
                    String out_trade_no = (String) map.get("out_trade_no");
                    String openidToUser = (String) map.get("openid");
                    log.info("total_fee ===========================> "+ map.get("total_fee"));
                    Double templePrice = new BigDecimal( (String) map.get("total_fee")).divide(new BigDecimal("100")).doubleValue();

                    //Integer price = (Integer) map.get("total_fee");
                    UserOrderFlow userOrderFlow = userPayOrder_service.selectUserOrderFlowByWechatTradeNo(out_trade_no);
                    if(userOrderFlow != null){

                        String openid = userPayOrder_service.selectToUserOpenidByOrderId(userOrderFlow.getUserOrderId());//导师openid
                        String accessToken = (String) servletContext.getAttribute("wechatAccessToken");
                        userOrderFlow.setStatus(UserOrderStatusEnum.PAID.getState());//已支付
                        userOrderFlow.setOperation("已支付");
                        userOrderFlow.setIsSuccess(1);
                        userPayOrder_service.updateUserOrderFlow(userOrderFlow);
                        UserOrderStatus status = new UserOrderStatus();
                        status.setCreateTime(userOrderFlow.getCreateTime());
                        status.setStatus(userOrderFlow.getStatus());
                        status.setUserOrderId(userOrderFlow.getUserOrderId());
                        userPayOrder_service.insertUserOrderStatus(status);

                        UserOrder userOrder = userPayOrder_service.selectUserOrderById(userOrderFlow.getUserOrderId());

                        UserWechat userWechat = userWechat_service.selectByMiniOpenid(openid);//导师
                        UserWechat userWechatToUser = userWechat_service.selectByMiniOpenid(openidToUser);//学员

                        TUser user = tUserMapper.selectUserByOpenid(openidToUser);//学员

                        if(userWechat != null && user != null){
                            log.info("微信公众号通知================================================>"+userWechat.getPlatform());
                            //  x-nMYhknvGkJq256WczOxg1cih9wm2LZMp9nnDS6CMg (新订单通知 导师)
                            //  yA6imDOE8YBiZJGq417cHz8OPfm97u8OWf0JNSGoDZ8 (购买成功通知 学员)
                            List<Map<String,String>> list = new LinkedList<>();
                            Map<String,String> map1 = new HashMap<>();
                            map1.put("value",user.getFullName());
                            list.add(map1);
                            map1 = new HashMap<>();
                            try{
                                map1.put("value",topicMapper.selectByPrimaryKey(userOrder.getTopicId()).getTopicName());
                            }catch (Exception e){
                                map1.put("value",userOrder.getQuestion());
                            }
                            list.add(map1);
                            map1 = new HashMap<>();
                            map1.put("value",templePrice+"");
                            list.add(map1);
                            map1 = new HashMap<>();
                            map1.put("value", userOrderFlow.getOperation());
                            list.add(map1);
                            map1 = new HashMap<>();
                            map1.put("value", DateFormatUtil.dateToString(new Date()));
                            list.add(map1);
                            //通知导师
                            wechatMiniUtil.sendTemplate(accessToken,"导师您好，您有一个新订单！",userWechat.getPlatform(),list,"如在24小时未处理订单，系统将自动拒绝该订单。立即进入订单详情！",userOrderFlow.getUserOrderId(),"x-nMYhknvGkJq256WczOxg1cih9wm2LZMp9nnDS6CMg");

                            if (userWechatToUser != null) {
                                //学员已关注公众号才发送模板消息
                                list = new LinkedList<>();
                                map1 = new HashMap<>();
                                map1.put("value",templePrice+"");
                                list.add(map1);
                                map1 = new HashMap<>();
                                try{
                                    map1.put("value",topicMapper.selectByPrimaryKey(userOrder.getTopicId()).getTopicName());
                                }catch (Exception e){
                                    map1.put("value",userOrder.getQuestion());
                                }
                                list.add(map1);
                                map1 = new HashMap<>();
                                map1.put("value",SecurityUtil.stringToMD5(userOrder.getId()+""));
                                list.add(map1);
                                //通知学员
                                wechatMiniUtil.sendTemplate(accessToken,"您的订单已支付成功！",userWechatToUser.getPlatform(),list,"导师将在24小时内处理订单，请耐心等待～",userOrderFlow.getUserOrderId(),"yA6imDOE8YBiZJGq417cHz8OPfm97u8OWf0JNSGoDZ8");
                            }
                        }else{
                            log.info("UserWechat 为空================================================>  "+openid);
                        }
                    }else{
                        log.info("微信支付异步处理出错 ==> userOrderFlow 为空...");
                    }
                    //必须向外写出，否则异步请求将继续执行
                    response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
                }
            }else{
                log.info("微信支付异步处理签名不一致");
                response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 微信支付退款异步通知方法
     * */
    public void payRefundNotify(HttpServletResponse response, HttpServletRequest request){
        try {
            BufferedReader reader = request.getReader();
            String temp = "";
            StringBuffer inputString = new StringBuffer();
            while ((temp = reader.readLine()) != null) {
                inputString.append(temp);
            }
            log.info(inputString.toString());
            Map<String, String> resultMap = XmlUtils.xmlToMap(inputString.toString());
            reader.close();
            if("SUCCESS".equals(resultMap.get("return_code"))){
                String reqInfo = resultMap.get("req_info");
                String mchKey = SecurityUtil.stringToMD5(key).toLowerCase();
                SecretKeySpec key = new SecretKeySpec(mchKey.getBytes(), "AES");
                String scInfo = SecurityUtil.decryptData(reqInfo,key);
                Map<String, String> infoMap = XmlUtils.xmlToMap(scInfo);
                infoMap.get("transaction_id");
                String orderNumber = infoMap.get("out_trade_no");
                infoMap.get("refund_id");
                infoMap.get("out_refund_no");
                infoMap.get("total_fee");
                String refundFee = infoMap.get("refund_fee");
                infoMap.get("refund_status");
                if(orderNumber != null && orderNumber.length() > 2){
                    UserOrderFlow userOrderFlow = userPayOrder_service.selectUserOrderFlowByWechatTradeNo(orderNumber);
                    if(userOrderFlow != null){
                        int price = Integer.parseInt(refundFee);
                        Double ps = price * 1.0 / 100;
                        UserOrder userOrder = userPayOrder_service.selectUserOrderById(userOrderFlow.getUserOrderId());
                        userOrderFlow.setStatus(UserOrderStatusEnum.REFUND.getState());//订单退款
                        userOrderFlow.setOperation("已退款,金额为：" + ps + "元");
                        userPayOrder_service.updateUserOrderFlow(userOrderFlow);//更新退款订单流水
                        userOrder.setStatus(UserOrderStatusEnum.REFUND.getState());//订单退款
                        userPayOrder_service.updateOrder(userOrder);
                    }
                }else{
                    log.info("单号为空，退款异步调用错误");
                }
                response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 企业付款给个人
     *
     * */
    public RestBean<?> payToUser(int amount,String name,String desc,HttpServletRequest request,String openid){
        String spbill_create_ip = IPUtil.getIpAddress(request);
        String api = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
        SortedMap<String, Object> params = new TreeMap<String, Object>();
        String partner_trade_no = ""+System.currentTimeMillis()+StringUtil.getRandom(5);//商户订单号
        params.put("mch_appid",appid);
        params.put("mchid",mchId);
        params.put("nonce_str",StringUtil.getRandom(32));
        params.put("partner_trade_no",partner_trade_no);
        params.put("amount",amount);
        params.put("openid",openid);
        params.put("check_name","FORCE_CHECK");
        params.put("re_user_name",name);
        params.put("spbill_create_ip",spbill_create_ip);
        params.put("desc",desc);//退款原因
        String sign = StringUtil.getMiniSign(params).append("key=" + key).toString();//key必须加一个
        params.put("sign", SecurityUtil.stringToMD5(sign).toUpperCase());
        String xml = StringUtil.toMiniWechatPayXml(params);
        params.put("sign",sign);

        try {
            URL url = new URL(api);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("POST");
            con.setUseCaches(false);
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
            OutputStream out = con.getOutputStream();
            out.write(xml.getBytes());
            out.flush();
            out.close();

            InputStream in = null;
            if (con.getResponseCode() == 200) {
                in = con.getInputStream();
            } else {
                in = con.getErrorStream();
                String temp = "";
                String result = "";
                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                while ((temp = br.readLine()) != null) {
                    result += temp;
                }
                log.info(result);
                return RestBean.buildError("wechat pay system error");
            }

            String temp = "";
            String result = "";
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            while ((temp = br.readLine()) != null) {
                result += temp;
            }
            Map<String, String> resultMap = XmlUtils.xmlToMap(result);
            if ("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))){
                //付款完成
            }
            log.info(result);
            return RestBean.buildSuccess("paying...");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return RestBean.buildError("wechat pay system error");
    }

}
